package zero.tech.games.gate.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import zero.tech.core.data.Resp;
import zero.tech.core.data.SimpleUser;
import zero.tech.games.common.Code;
import zero.tech.games.common.GameConfig;
import zero.tech.games.common.LockConsts;
import zero.tech.games.common.PipeiGroup;
import zero.tech.games.common.RedisConsts;
import zero.tech.games.common.TopicOrder;
import zero.tech.games.entity.games.CfServer;
import zero.tech.games.entity.games.Club;
import zero.tech.games.entity.games.ClubGameRule;
import zero.tech.games.gate.data.entity.ClubPipei;
import zero.tech.games.gate.data.res.ResPipeiQueueBatchSize;
import zero.tech.games.gate.data.res.ResPipeiQueueBatchSize.PipeiQueueRule;
import zero.tech.games.gate.data.res.ResPipeiQueueSize;
import zero.tech.games.gate.hot.CfUtil;
import zero.tech.games.gate.hot.ClubUtil;
import zero.tech.redis.cache.RedisUtil;
import zero.tech.redis.lock.RedisLockUtil;
import zero.tech.redis.lock.RedisLockUtil.LockMethod;
import zero.tech.redis.topic.TopicChannelType;
import zero.tech.redis.topic.service.api.IRedisMsgService;

@Component
public class PipeiUtil {
	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private RedisLockUtil redisLockUtil;
	@Autowired
	private IRedisMsgService redisMsgService;
	@Autowired
	private CfUtil cfServerUtil;
	@Autowired
	private ClubUtil clubUtil;
	@Autowired
	private @Qualifier("restTemplate") RestTemplate restTemplate;
	
	public Resp removeFromQueue(SimpleUser simpleUser) {
		return redisLockUtil.lockMethod(new LockMethod<Resp>() {
			@Override
			public Resp lockRun() {
				int uid=simpleUser.getUid();
				Map<Object,Object> map=redisUtil.hgetAll(RedisConsts.B_PIPEIQUEUE);
				for(Entry<Object,Object> entry:map.entrySet()) {
					String rule_id_str=(String) entry.getKey();
					int rule_id=Integer.valueOf(rule_id_str);
					Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
					String str=(String) entry.getValue();
					if(StringUtils.isNotBlank(str)) {
						Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
						simpleUserMap.putAll(tmp);
					}
					if(simpleUserMap.containsKey(uid)) {
						simpleUserMap.remove(uid);
						if(simpleUserMap.isEmpty()) {
							redisUtil.hdel(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id));
						}else {
							redisUtil.hset(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id), JSONObject.toJSONString(simpleUserMap));
						}
						return Resp.build(Code.OK, "移除队列成功");
					}
				}
				return Resp.build(Code.OK, "移除队列成功");
			}
		}, LockConsts.PIPEI_LOCK, 30);
	}
	
	public Resp addToQueue(ClubGameRule clubGameRule, SimpleUser simpleUser) {
		return redisLockUtil.lockMethod(new LockMethod<Resp>() {
			@Override
			public Resp lockRun() {
				int rule_id=clubGameRule.getRule_id();
				int fzb_playernum=clubGameRule.getFzb_playernum();
				int uid=simpleUser.getUid();
				String str=(String) redisUtil.hget(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id));
				Map<Integer,SimpleUser> map=new HashMap<>();
				if(StringUtils.isNotBlank(str)) {
					Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
					map.putAll(tmp);
				}
				if(map.size()>=fzb_playernum) {
					return Resp.build(Code.OK, "玩家正在陆续进入房间,请稍后再试!");
				}
				map.put(uid, simpleUser);
				redisUtil.hset(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id), JSONObject.toJSONString(map));
				return Resp.build(Code.OK, "加入匹配成功");
			}
		}, LockConsts.PIPEI_LOCK, 30);
	}

	protected boolean groupEnterGame(CfServer cfServer, Club club, ClubGameRule clubGameRule, List<PipeiGroup> groups, Integer fzb_playernum) {
		int game_id=cfServer.getGame_id();
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("configStr", clubGameRule.getConfig_str());
		paramMap.put("clubStr", JSONObject.toJSONString(club));
		paramMap.put("game_id", String.valueOf(game_id));
		paramMap.put("group_str", JSONObject.toJSONString(groups));
		Resp resp=restTemplate.postForObject("http://"+cfServer.getService_id()+cfServer.getContext_url()+"/create-pipei-room", paramMap, Resp.class);
		if(Code.OK.equals(resp.getCode())) {
			String str=resp.getParam().toJSONString();
			String str1=JSONObject.toJSONString(groups);
			JSONObject obj=new JSONObject();
			obj.put("room_nodes", str);
			obj.put("groups",str1);
			obj.put("fzb_playernum", fzb_playernum);
			redisMsgService.pulishRedisTopic(TopicChannelType.CLUB_MEMBER_PIPEI_NOTIFY_ENTER_GAME, TopicOrder.NOTIFY_ENTER_GAME, obj);
			return true;
		}
		return false;
	}

	protected List<PipeiGroup> group(ClubGameRule clubGameRule, Map<Integer, SimpleUser> simpleUserMap) {
		List<PipeiGroup> list=new ArrayList<PipeiGroup>();
		GameConfig gameConfig = JSONObject.parseObject(clubGameRule.getConfig_str(), GameConfig.class);
		int max_player=gameConfig.getMax_player();
		int size=simpleUserMap.size();
		List<SimpleUser> simpleUsers=new ArrayList<>();
		simpleUsers.addAll(simpleUserMap.values());
		Collections.shuffle(simpleUsers);
		int count=size/max_player;
		for(int i=0;i<count;i++) {
			Map<Integer,SimpleUser> map=new HashMap<>();
			List<SimpleUser> tmp=new ArrayList<>();
			int start=i*max_player;
			int end=i*max_player+max_player;
			if(start<=size) {
				end=end>=size?size:end;
				tmp.addAll(simpleUsers.subList(i*max_player, i*max_player+max_player));
				for(SimpleUser simpleUser:tmp) {
					map.put(simpleUser.getUid(), simpleUser);
				}
				PipeiGroup pipeiGroup = new PipeiGroup();
				pipeiGroup.getSimpleUsers().putAll(map);
				list.add(pipeiGroup);
			}
		}
		return list;
	}

	public boolean inQueue(int uid) {
		Map<Object,Object> map=redisUtil.hgetAll(RedisConsts.B_PIPEIQUEUE);
		for(Entry<Object,Object> entry:map.entrySet()) {
			String str=(String) entry.getValue();
			Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
			if(StringUtils.isNotBlank(str)) {
				Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
				simpleUserMap.putAll(tmp);
			}
			if(simpleUserMap.containsKey(uid)) {
				return true;
			}
		}
		return false;
	}

	public void checkGameNotifyEnter() {
		redisLockUtil.lockMethod(new LockMethod<Boolean>() {
			@Override
			public Boolean lockRun() {
				Map<Object,Object> map=redisUtil.hgetAll(RedisConsts.B_PIPEIQUEUE);
				for(Entry<Object,Object> entry:map.entrySet()) {
					String rule_id_str=(String) entry.getKey();
					int rule_id=Integer.valueOf(rule_id_str);
					ClubGameRule clubGameRule=clubUtil.loadHotClubGameRule(rule_id);
					int game_id=clubGameRule.getGame_id();
					CfServer cfServer=cfServerUtil.getCfServer(game_id);
					int club_id=clubGameRule.getClub_id();
					Club club=clubUtil.loadHotClub(club_id);
					Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
					String str=(String) entry.getValue();
					if(StringUtils.isNotBlank(str)) {
						Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
						simpleUserMap.putAll(tmp);
					}
					if(simpleUserMap.size()>=clubGameRule.getFzb_playernum()) {
						//开始广播达到最大人数
						List<PipeiGroup> groups=group(clubGameRule,simpleUserMap);
						boolean ok=groupEnterGame(cfServer, club, clubGameRule, groups,clubGameRule.getFzb_playernum());
						if(ok) {
							redisUtil.hdel(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id));
						}
					}
				}
				return null;
			}
		}, LockConsts.PIPEI_LOCK_NOTIFY_ENTER, 30);
	}

	public ClubPipei getClubPipei(Integer uid) {
		Map<Object,Object> map=redisUtil.hgetAll(RedisConsts.B_PIPEIQUEUE);
		for(Entry<Object,Object> entry:map.entrySet()) {
			String rule_id_str=(String) entry.getKey();
			int rule_id=Integer.valueOf(rule_id_str);
			Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
			String str=(String) entry.getValue();
			if(StringUtils.isNotBlank(str)) {
				Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
				simpleUserMap.putAll(tmp);
			}
			if(simpleUserMap.containsKey(uid)) {
				ClubGameRule clubGameRule=clubUtil.loadHotClubGameRule(rule_id);
				int club_id=clubGameRule.getClub_id();
				ClubPipei clubPipei= new ClubPipei();
				clubPipei.setClub_id(club_id);
				clubPipei.setClubGameRule(clubGameRule);
				clubPipei.setPlayer_num(simpleUserMap.size());
				return clubPipei;
			}
		}
		return null;
	}

	public Resp getPipeiQueueSize(SimpleUser simpleUser, int rule_id) {
		ResPipeiQueueSize resPipeiQueueSize=(ResPipeiQueueSize) redisUtil.get(RedisConsts.HOT_SECOND_PIPEI_SIZE+"_"+rule_id);
		if(resPipeiQueueSize==null) {
			String str=(String) redisUtil.hget(RedisConsts.B_PIPEIQUEUE, String.valueOf(rule_id));
			Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
			if(StringUtils.isNotBlank(str)) {
				Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
				simpleUserMap.putAll(tmp);
			}
			resPipeiQueueSize=new ResPipeiQueueSize();
			resPipeiQueueSize.setRule_id(rule_id);
			resPipeiQueueSize.setSize(simpleUserMap==null?0:simpleUserMap.size());
			redisUtil.set(RedisConsts.HOT_SECOND_PIPEI_SIZE+"_"+rule_id, resPipeiQueueSize,10);
		}
		return Resp.build(Code.OK, "获取成功",resPipeiQueueSize);
	}

	public Resp getPipeiQueueSize(SimpleUser simpleUser, List<Integer> rule_ids) {
		String[] strs=new String[rule_ids.size()];
		int index=0;
		String key="";
		for(int rule_id:rule_ids) {
			strs[index++]=String.valueOf(rule_id);
			key+="_"+rule_id;
		}
		ResPipeiQueueBatchSize resPipeiQueueBatchSize=(ResPipeiQueueBatchSize) redisUtil.get(RedisConsts.HOT_SECOND_PIPEI_SIZE_BATCH+key);
		List<PipeiQueueRule> list=new ArrayList<>();
		if(resPipeiQueueBatchSize==null) {
			Map<String, String> map=redisUtil.hmget(RedisConsts.B_PIPEIQUEUE, strs);
			for(Entry<String,String> entry:map.entrySet()) {
				String rule_id=entry.getKey();
				String str=entry.getValue();
				Map<Integer,SimpleUser>simpleUserMap=new HashMap<>();
				if(StringUtils.isNotBlank(str)) {
					Map<Integer,SimpleUser> tmp=JSONObject.parseObject(str, new TypeReference<Map<Integer,SimpleUser>>(){});
					simpleUserMap.putAll(tmp);
				}
				int pipei_num=simpleUserMap.size();
				ClubGameRule clubGameRule=clubUtil.loadHotClubGameRule(Integer.valueOf(rule_id));
				int fzb_playernum=clubGameRule.getFzb_playernum();
				list.add(new PipeiQueueRule(rule_id,pipei_num,fzb_playernum));
			}
			resPipeiQueueBatchSize=new ResPipeiQueueBatchSize();
			resPipeiQueueBatchSize.getList().addAll(list);
			redisUtil.set(RedisConsts.HOT_SECOND_PIPEI_SIZE_BATCH+key, resPipeiQueueBatchSize,10);
		}
		return Resp.build(Code.OK, "获取成功",resPipeiQueueBatchSize);
	}
}
